//
// Created by root on 4/29/17.
//

#include <memory.h>
#include "../runner.h"

/**
 * cases for number real when arguments are not reals
 * */

#define OP_REAL_FIRST_ARG_INVALID(_op) Cell* arg_x = make_string(global_scheme, "A_STRING"); \
    Cell* arg_y = make_integer(global_scheme, 2); \
    Cell* r = real_##_op \
    (global_scheme, arg_x, arg_y)

#define OP_REAL_SECOND_ARG_INVALID(_op) Cell* arg_x = make_integer(global_scheme, 1); \
    Cell* arg_y = make_string(global_scheme, "A_STRING"); \
    Cell* r = real_##_op \
    (global_scheme, arg_x, arg_y)

//real_add
static void test_real_add_when_first_arg_is_not_real() {
    OP_REAL_FIRST_ARG_INVALID(add);
    TEST_INVALID_TYPE_EXCEPTION(r);
}

static void test_real_add_when_second_arg_is_not_real() {
    OP_REAL_SECOND_ARG_INVALID(add);
    TEST_INVALID_TYPE_EXCEPTION(r);
}

//real_mul
static void test_real_mul_when_first_arg_is_not_real() {
    OP_REAL_FIRST_ARG_INVALID(mul);
    TEST_INVALID_TYPE_EXCEPTION(r);
}

static void test_real_mul_when_second_arg_is_not_real() {
    OP_REAL_SECOND_ARG_INVALID(mul);
    TEST_INVALID_TYPE_EXCEPTION(r);
}

//real_sub
static void test_real_sub_when_first_arg_is_not_real() {
    OP_REAL_SECOND_ARG_INVALID(sub);
    TEST_INVALID_TYPE_EXCEPTION(r);
}

static void test_real_sub_when_second_arg_is_not_real() {
    OP_REAL_SECOND_ARG_INVALID(sub);
    TEST_INVALID_TYPE_EXCEPTION(r);
}

//real_div
static void test_real_div_when_first_arg_is_not_real() {
    OP_REAL_SECOND_ARG_INVALID(div);
    TEST_INVALID_TYPE_EXCEPTION(r);
}

static void test_real_div_when_second_arg_is_not_real() {
    OP_REAL_SECOND_ARG_INVALID(div);
    TEST_INVALID_TYPE_EXCEPTION(r);
}

/**
 * cases for number div when divided by zero
 * */

//real_div
static void test_real_div_when_divided_by_int_zero() {
    Cell* arg_x = make_integer(global_scheme, 1);
    Cell* arg_y = make_integer(global_scheme, 0);
    Cell* r = real_div(global_scheme, arg_x, arg_y);
    TEST_DIVISION_BY_ZERO(r);
}

static void test_real_div_when_divided_by_fraction_zero() {
    Cell* arg_x = make_integer(global_scheme, 1);
    Cell* arg_y = make_fraction(global_scheme, make_integer(global_scheme, 0), make_integer(global_scheme, 1));
    Cell* r = real_div(global_scheme, arg_x, arg_y);
    TEST_DIVISION_BY_ZERO(r);
}

static void test_real_div_when_divided_by_decimal_zero() {
    Cell* arg_x = make_integer(global_scheme, 1);
    Cell* arg_y = make_decimal(global_scheme, 0.0);
    Cell* r = real_div(global_scheme, arg_x, arg_y);
    TEST_DIVISION_BY_ZERO(r);
}

//TODO
int main(int argc, char **argv) {
    const struct CMUnitTest tests[] = {
            /*real_add*/
            cmocka_unit_test(test_real_add_when_first_arg_is_not_real),
            cmocka_unit_test(test_real_add_when_second_arg_is_not_real),
            /*real_mul*/
            cmocka_unit_test(test_real_mul_when_first_arg_is_not_real),
            cmocka_unit_test(test_real_mul_when_second_arg_is_not_real),
            /*real_sub*/
            cmocka_unit_test(test_real_sub_when_first_arg_is_not_real),
            cmocka_unit_test(test_real_sub_when_second_arg_is_not_real),
            /*real_div*/
            cmocka_unit_test(test_real_div_when_first_arg_is_not_real),
            cmocka_unit_test(test_real_div_when_second_arg_is_not_real),
            cmocka_unit_test(test_real_div_when_divided_by_int_zero),
            cmocka_unit_test(test_real_div_when_divided_by_fraction_zero),
            cmocka_unit_test(test_real_div_when_divided_by_decimal_zero),
    };
    return cmocka_run_group_tests(tests, setup_scheme, teardown_scheme);
}
